package co.com.timer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.ConcurrencyManagement;
import javax.ejb.ConcurrencyManagementType;
import javax.ejb.Local;
import javax.ejb.Lock;
import javax.ejb.LockType;
import javax.ejb.Schedule;
import javax.ejb.ScheduleExpression;
import javax.ejb.SessionContext;
import javax.ejb.Singleton;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;

@Singleton
@Local(CreditCardTransactionProcessingLocalBusiness.class)
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class CreditCardTransactionProcessingBean implements CreditCardTransactionProcessingLocalBusiness {

	@Resource
	private SessionContext context;

	@Resource
	private TimerService timerService;

	private final List<CreditCardTransaction> pendingTransactions = new ArrayList<>();

	@PostConstruct
	public void init() {
		scheduleProcessing(new ScheduleExpression().second("*/5").minute("*").hour("*"));
	}

	@Timeout
	//@Schedule(second="*/5", minute="*", hour="*")
	@Lock(LockType.WRITE)
	public void processViaTimeout(final Timer timer) {
		this.process();
	}

	@Override
	public void add(CreditCardTransaction transaction) throws IllegalArgumentException {
		if (transaction == null) {
			throw new IllegalArgumentException("transaction must be specified");
		}
		pendingTransactions.add(transaction);
		System.out.println("Added transaction pending to be processed: " + transaction);
	}

	@Override
	@Lock(LockType.READ)
	public List<CreditCardTransaction> getPendingTransactions() {
		return Collections.unmodifiableList(pendingTransactions);
	}

	@Override
	@Lock(LockType.WRITE)
	public void process() {
		if (pendingTransactions.isEmpty()) {
			System.out.println("Nothing to process");
		}
		else {
			for (CreditCardTransaction transaction : pendingTransactions)
			{ 
				System.out.println("Processed transaction: " + transaction);
			}
		}
		pendingTransactions.clear();	
	}

	@Override
	public Date scheduleProcessing(ScheduleExpression expression) throws IllegalArgumentException {
		if (expression == null) {
			throw new IllegalArgumentException("Timer expression must be specified");
		}
		TimerService timerService = context.getTimerService();
		Timer timer = timerService.createCalendarTimer(expression);
		Date next = timer.getNextTimeout();
		System.out.println("Created " + timer + " to process transactions; " +
				"next fire is at: " + next);
		return next;
	}	
}